"""
自动将输入的.java文件转化为简单的类图
"""
import os
import re

protectType = "(private|protected|public)"
rClass = r"public\s((abstract\s)?(interface|class))\s(\w+)(\sextends\s(\w+))?\s(implements\s(\w+))?"
rProperty = protectType + r"\s(static\s)?(final\s)?(abstract\s)?([a-zA-Z<>]+)\s(\w+)(\(.*?\))?"
protectTypeDict = {'private': '-', 'protected': '#', 'public': '+'}


def doUML(path):
    """
    画UML类图
    :param path: 文件路径
    :return:
    """
    outLines = []
    with open(path, 'r', encoding='utf-8') as f:
        lines = ''.join(f.readlines())
        myClass = re.search(rClass, lines)
        if myClass is not None:
            print(myClass.groups())
            classType = myClass.group(1)
            className = myClass.group(4)
            parentName = myClass.group(6)
            interfaceName = myClass.group(8)
            if parentName is not None:
                outLines.append(f"{parentName} <|-- {className}\n")
            if interfaceName is not None:
                outLines.append(f"{interfaceName} <|.. {className}\n")
            outLines.append(f"{classType} {className} {{\n")

            rConstruct = protectType + r"\s" + className + r"(\(.*?\))"
            construct = re.search(rConstruct, lines, flags=re.S)
            if construct is not None:
                outLines.append(f"\t{protectTypeDict[construct.group(1)]} {className}{construct.group(2)}\n")
                print(outLines)

            # 匹配属性和方法
            aa = re.findall(rProperty, lines)
            # print(len(aa))
            propertyList = []
            methodList = []
            for a in aa:
                # print(a)
                aProtect = a[0]
                aStatic = '{' + a[1][:-1] + '} ' if a[1] != '' else ''
                aAbstract = '{' + a[3][:-1] + '} ' if a[3] != '' else ''
                aType = a[4]
                aName = a[5]
                aParam = a[6]
                if aType in ['interface', 'class']:
                    continue
                if aParam == '':
                    # 没有参数说明是属性
                    propertyList.append(f"\t{protectTypeDict[aProtect]} {aStatic}{aName}:{aType}\n")
                else:
                    # 有参数说明是方法
                    methodList.append(f"\t{protectTypeDict[aProtect]} {aStatic}{aAbstract}{aName}{aParam}:{aType}\n")

            outLines.extend(propertyList)
            outLines.extend(methodList)
            outLines.append("}\n\n")
            print(outLines)
    with open(f"a.puml", "a+") as f:
        f.writelines(outLines)


def scanPath(path: str, prefix="", suffix=""):
    """
    扫描并过滤文件
    :param path: 目录路径, 可以是相对或者绝对
    :param prefix: 前缀
    :param suffix: 后缀
    :return: None
    """
    path = os.path.abspath(path)  # 获取绝对路径
    if not os.path.isdir(path):  # 是否是目录
        raise ValueError(f"路径{path} 不是一个合法目录")
    print(f"扫描目录{path}")
    fileList = os.listdir(path)
    for file in fileList:
        absFile = os.path.join(path, file)
        if os.path.isdir(absFile):
            # scanPath(absFile)
            pass
        else:
            if file.endswith(suffix) and file.startswith(prefix):
                doUML(absFile)


def main():
    with open("a.puml", "w") as f:
        f.write('@startuml\n')
    scanPath("./src")
    with open("a.puml", "a+") as f:
        f.write('@enduml')


if __name__ == '__main__':
    main()
